// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "cc/debug/lap_timer.h"

#include "base/logging.h"

namespace cc {

namespace {

    // Returns the offset from the origin from the ThreadTicks time source.
    // TimeTicks is used as a fallback if ThreadTicks is not available on the
    // current platform.
    base::TimeDelta Now()
    {
        return base::ThreadTicks::IsSupported()
            ? base::ThreadTicks::Now() - base::ThreadTicks()
            : base::TimeTicks::Now() - base::TimeTicks();
    }

    // Default values.
    static const int kTimeLimitMillis = 3000;
    static const int kWarmupRuns = 5;
    static const int kTimeCheckInterval = 10;

} // namespace

LapTimer::LapTimer(int warmup_laps,
    base::TimeDelta time_limit,
    int check_interval)
    : warmup_laps_(warmup_laps)
    , remaining_warmups_(0)
    , remaining_no_check_laps_(0)
    , time_limit_(time_limit)
    , check_interval_(check_interval)
{
    DCHECK_GT(check_interval, 0);
    Reset();
}

LapTimer::LapTimer()
    : LapTimer(kWarmupRuns,
        base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
        kTimeCheckInterval)
{
    if (base::ThreadTicks::IsSupported())
        base::ThreadTicks::WaitUntilInitialized();
}

void LapTimer::Reset()
{
    accumulator_ = base::TimeDelta();
    num_laps_ = 0;
    remaining_warmups_ = warmup_laps_;
    remaining_no_check_laps_ = check_interval_;
    Start();
}

void LapTimer::Start()
{
    start_time_ = Now();
}

bool LapTimer::IsWarmedUp() { return remaining_warmups_ <= 0; }

void LapTimer::NextLap()
{
    if (!IsWarmedUp()) {
        --remaining_warmups_;
        if (IsWarmedUp()) {
            Start();
        }
        return;
    }
    ++num_laps_;
    --remaining_no_check_laps_;
    if (!remaining_no_check_laps_) {
        base::TimeDelta now = Now();
        accumulator_ += now - start_time_;
        start_time_ = now;
        remaining_no_check_laps_ = check_interval_;
    }
}

bool LapTimer::HasTimeLimitExpired() { return accumulator_ >= time_limit_; }

bool LapTimer::HasTimedAllLaps() { return !(num_laps_ % check_interval_); }

float LapTimer::MsPerLap()
{
    DCHECK(HasTimedAllLaps());
    return accumulator_.InMillisecondsF() / num_laps_;
}

float LapTimer::LapsPerSecond()
{
    DCHECK(HasTimedAllLaps());
    return num_laps_ / accumulator_.InSecondsF();
}

int LapTimer::NumLaps() { return num_laps_; }

} // namespace cc
